package com.jt.resource.aspect;

import com.jt.resource.annotation.RequiredLog;
import com.jt.resource.pojo.Log;
import com.jt.resource.service.RemoteLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Date;

@Slf4j
@Aspect
@Component
public class LogAspect {
    /**
     * 注解方式的切入点表达式定义
     */
    @Pointcut("@annotation(com.jt.resource.annotation.RequiredLog)")
    public void doLog(){
        //只负责,承载切入点表达式的定义
    }

    /**
     * 可以控制目标方法的执行
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("doLog()")
    public Object doInvoke(ProceedingJoinPoint joinPoint) throws Throwable{
        int status=1;
        long time = 0;
        String error=null;
        long t1=System.currentTimeMillis();
        log.debug("Before {}",t1);
        //执行目标方法,其他通知方法
        try {
            Object result = joinPoint.proceed();
            long t2=System.currentTimeMillis();
            time=t2-t1;
            log.debug("After {}",t2);
            return result;
        }catch (Throwable e){
            status=0;
            long t3=System.currentTimeMillis();
            time=t3-t1;
            log.debug("Exception {}",t3);
            error=e.getMessage();
            throw e;
        }finally {
            log.debug("execute method time :{}",time);
            saveLog(joinPoint,error,status,time);
        }
    }

    //保存日志
    private void saveLog(ProceedingJoinPoint joinPoint,String error,int status,long time) throws NoSuchMethodException, IOException {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip=request.getRemoteAddr();

        String username=(String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        Class<?> targetClass = joinPoint.getTarget().getClass();
        MethodSignature signature =(MethodSignature) joinPoint.getSignature();
        Method targetMethod = targetClass.getDeclaredMethod(signature.getName(), signature.getParameterTypes());
        RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class);
        String operation = requiredLog.value();

        String methodName=targetClass.getName()+"."+targetMethod.getName();

        String params = new ObjectMapper().writeValueAsString(joinPoint.getArgs());
        Log log=new Log();
        log.setIp(ip);
        log.setUsername(username);
        log.setCreatedTime(new Date());
        log.setOperation(operation);
        log.setMethod(methodName);
        log.setParams(params);
        log.setTime(time);
        log.setStatus(status);
        log.setError(error);

        remoteLogService.insertLog(log);

    }
    @Autowired
    private RemoteLogService remoteLogService;
}
